#include<arm_neon.h>
#include<string.h>
#include<iostream>
#include<fstream>
using namespace std;
const int N = 4100;
float32_t nums[N][N];
int n;

long long head, tail, freq;
struct timespec sts, ets;
time_t dsec;
long dnsec;

ifstream fin("input.txt");
ofstream fout("output.txt");

void Gauss_unalign(int n) {
	for (int k = 1; k <= n; ++k) {
		float32x4_t vt = vmovq_n_f32(nums[k][k]);
		int j = k + 1;
		for (; j + 4 <= n; j += 4) {
			float32x4_t va = vld1q_f32(&nums[k][j]);
			va = vdivq_f32(va, vt);
			vst1q_f32(&nums[k][j], va);
		}
		for (; j <= n; ++j)
			nums[k][j] /= nums[k][k];
		nums[k][k] = 1.0;
		for (int i = k + 1; i <= n; ++i) {
			float32x4_t vik = vmovq_n_f32(nums[i][k]);
			int j = k + 1;
			for (; j + 4 <= n; j += 4) {
				float32x4_t vkj = vld1q_f32(&nums[k][j]);
				float32x4_t vij = vld1q_f32(&nums[i][j]);
				float32x4_t vx = vmulq_f32(vik, vkj);
				vij = vsubq_f32(vij, vx);
				vst1q_f32(&nums[i][j], vij);
			}
			for (; j <= n; ++j)
				nums[i][j] -= nums[i][k] * nums[k][j];
			nums[i][k] = 0;
		}
	}

}
void Gauss_align(int n) {
	for (int k = 1; k <= n; ++k) {
		float32x4_t vt = vmovq_n_f32(nums[k][k]);
		int j = k + 1;


		while (j <= n && ((unsigned long long) & nums[k][j] % 16 != 0)) {
			nums[k][j] /= nums[k][k];
			++j;
		}


		for (; j + 4 <= n; j += 4) {
			float32x4_t va = vld1q_f32(&nums[k][j]);
			va = vdivq_f32(va, vt);
			vst1q_f32(&nums[k][j], va);
		}
		for (; j <= n; ++j)
			nums[k][j] /= nums[k][k];
		nums[k][k] = 1.0;
		for (int i = k + 1; i <= n; ++i) {
			float32x4_t vik = vmovq_n_f32(nums[i][k]);
			int j = k + 1;


			while (j <= n && ((unsigned long long) & nums[k][j] % 16 != 0)) {
				nums[i][j] -= nums[i][k] * nums[k][j];
				++j;
			}


			for (; j + 4 <= n; j += 4) {
				float32x4_t vkj = vld1q_f32(&nums[k][j]);
				float32x4_t vij = vld1q_f32(&nums[i][j]);
				float32x4_t vx = vmulq_f32(vik, vkj);
				vij = vsubq_f32(vij, vx);
				vst1q_f32(&nums[i][j], vij);
			}


			for (; j <= n; ++j)
				nums[i][j] -= nums[i][k] * nums[k][j];
			nums[i][k] = 0;
		}
	}

}
void Gauss(int n) {
	for (int k = 1; k <= n; ++k) {
		for (int j = k + 1; j <= n; ++j)nums[k][j] /= nums[k][k];
		nums[k][k] = 1;
		for (int i = k + 1; i <= n; ++i) {
			for (int j = k + 1; j <= n; ++j)
				nums[i][j] -= nums[i][k] * nums[k][j];
			nums[i][k] = 0;
		}
	}
}

void Gauss_A3(int n) {
	for (int k = 1; k <= n; ++k) {
		int j = k + 1;
		while (j <= n && ((unsigned long long) & nums[k][j] % 16 != 0)) {
			nums[k][j] /= nums[k][k];
			++j;
		}
		float32x4_t vt = vmovq_n_f32(nums[k][k]);
		for (; j + 4 <= n; j += 4) {
			float32x4_t va = vld1q_f32(&nums[k][j]);
			va = vdivq_f32(va, vt);
			vst1q_f32(&nums[k][j], va);
		}
		for (; j <= n; ++j)
			nums[k][j] /= nums[k][k];
		nums[k][k] = 1.0;
		for (int i = k + 1; i <= n; ++i) {
			float32x4_t vik = vmovq_n_f32(nums[i][k]);
			int j = k + 1;
			for (; j + 4 <= n; j += 4) {
				float32x4_t vkj = vld1q_f32(&nums[k][j]);
				float32x4_t vij = vld1q_f32(&nums[i][j]);
				float32x4_t vx = vmulq_f32(vik, vkj);
				vij = vsubq_f32(vij, vx);
				vst1q_f32(&nums[i][j], vij);
			}
			for (; j <= n; ++j)
				nums[i][j] -= nums[i][k] * nums[k][j];
			nums[i][k] = 0;
		}
	}

}

void Gauss_A4(int n) {
	for (int k = 1; k <= n; ++k) {
		float32x4_t vt = vmovq_n_f32(nums[k][k]);
		int j = k + 1;
		for (; j + 4 <= n; j += 4) {
			float32x4_t va = vld1q_f32(&nums[k][j]);
			va = vdivq_f32(va, vt);
			vst1q_f32(&nums[k][j], va);
		}
		for (; j <= n; ++j)
			nums[k][j] /= nums[k][k];
		nums[k][k] = 1.0;
		for (int i = k + 1; i <= n; ++i) {
			float32x4_t vik = vmovq_n_f32(nums[i][k]);
			int j = k + 1;
			while (j <= n && ((unsigned long long) & nums[k][j] % 16 != 0)) {
				nums[i][j] -= nums[i][k] * nums[k][j];
				++j;
			}
			for (; j + 4 <= n; j += 4) {
				float32x4_t vkj = vld1q_f32(&nums[k][j]);
				float32x4_t vij = vld1q_f32(&nums[i][j]);
				float32x4_t vx = vmulq_f32(vik, vkj);
				vij = vsubq_f32(vij, vx);
				vst1q_f32(&nums[i][j], vij);
			}
			for (; j <= n; ++j)
				nums[i][j] -= nums[i][k] * nums[k][j];
			nums[i][k] = 0;
		}
	}

}
void Gauss_A1(int n) {
	for (int k = 1; k <= n; ++k) {
		float32x4_t vt = vmovq_n_f32(nums[k][k]);
		int j = k + 1;
		for (; j + 4 <= n; j += 4) {
			float32x4_t va = vld1q_f32(&nums[k][j]);
			va = vdivq_f32(va, vt);
			vst1q_f32(&nums[k][j], va);
		}
		for (; j <= n; ++j)
			nums[k][j] /= nums[k][k];
		nums[k][k] = 1.0;

		for (int i = k + 1; i <= n; ++i) {
			for (int j = k + 1; j <= n; ++j)
				nums[i][j] -= nums[i][k] * nums[k][j];
			nums[i][k] = 0;
		}
	}

}

void Gauss_A2(int n) {
	for (int k = 1; k <= n; ++k) {
		for (int j = k + 1; j <= n; ++j)nums[k][j] /= nums[k][k];
		nums[k][k] = 1;
		for (int i = k + 1; i <= n; ++i) {
			float32x4_t vik = vmovq_n_f32(nums[i][k]);
			int j = k + 1;
			for (; j + 4 <= n; j += 4) {
				float32x4_t vkj = vld1q_f32(&nums[k][j]);
				float32x4_t vij = vld1q_f32(&nums[i][j]);
				float32x4_t vx = vmulq_f32(vik, vkj);
				vij = vsubq_f32(vij, vx);
				vst1q_f32(&nums[i][j], vij);
			}
			for (; j <= n; ++j)
				nums[i][j] -= nums[i][k] * nums[k][j];
			nums[i][k] = 0;
		}
	}

}

void print_result(string str) {
	dsec = ets.tv_sec - sts.tv_sec;
	dnsec = ets.tv_nsec - sts.tv_nsec;
	if (dnsec < 0) {
		dsec--;
		dnsec += 1000000000ll;
	}
	ofstream of_result("/home/s2011354/result.txt", ios::app);
	of_result << str << " with n = " << n << " time = " << dsec << "." << dnsec << "s" << endl;
	of_result.close();

}
int main() {
	fin.open("input.txt");
	fin.close();

	fin.open("input.txt");
	fout.open("output.txt");
	fin >> n;
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= n; ++j)
			fin >> nums[i][j];
	fin.close();
	//timer
	timespec_get(&sts, TIME_UTC);
	Gauss(n);
	timespec_get(&ets, TIME_UTC);
	print_result("serial gauss");

		for (int i = 1; i <= n; ++i) {
			for (int j = 1; j <= n; ++j)
				fout << nums[i][j] << " ";
			fout << endl;
		}
	fout.close();
	memset(nums, 0, sizeof nums);


	fin.open("input.txt");
	fout.open("output.txt");
	fin >> n;
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= n; ++j)
			fin >> nums[i][j];
	fin.close();
	//timer
	timespec_get(&sts, TIME_UTC);
	Gauss_unalign(n);
	timespec_get(&ets, TIME_UTC);
	print_result("neon gauss memory unaligned");

		for (int i = 1; i <= n; ++i) {
			for (int j = 1; j <= n; ++j)
				fout << nums[i][j] << " ";
			fout << endl;
		}
	fout.close();
	memset(nums, 0, sizeof nums);



	fin.open("input.txt");
	fout.open("output.txt");
	fin >> n;
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= n; ++j)
			fin >> nums[i][j];
	fin.close();
	//timer
	timespec_get(&sts, TIME_UTC);
	Gauss_align(n);
	timespec_get(&ets, TIME_UTC);
	print_result("neon gauss memory aligned");

		for (int i = 1; i <= n; ++i) {
			for (int j = 1; j <= n; ++j)
				fout << nums[i][j] << " ";
			fout << endl;
		}
	fout.close();
	memset(nums, 0, sizeof nums);


	fin.open("input.txt");
	fout.open("output.txt");
	fin >> n;
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= n; ++j)
			fin >> nums[i][j];
	fin.close();
	//timer
	timespec_get(&sts, TIME_UTC);
	Gauss_A1(n);
	timespec_get(&ets, TIME_UTC);
	print_result("arm gauss A1");

		for (int i = 1; i <= n; ++i) {
			for (int j = 1; j <= n; ++j)
				fout << nums[i][j] << " ";
			fout << endl;
		}
	fout.close();
	memset(nums, 0, sizeof nums);

	fin.open("input.txt");
	fout.open("output.txt");
	fin >> n;
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= n; ++j)
			fin >> nums[i][j];
	fin.close();
	//timer
	timespec_get(&sts, TIME_UTC);
	Gauss_A2(n);
	timespec_get(&ets, TIME_UTC);
	print_result("arm gauss A2");

		for (int i = 1; i <= n; ++i) {
			for (int j = 1; j <= n; ++j)
				fout << nums[i][j] << " ";
			fout << endl;
		}
	fout.close();
	memset(nums, 0, sizeof nums);

	fin.open("input.txt");
	fout.open("output.txt");
	fin >> n;
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= n; ++j)
			fin >> nums[i][j];
	fin.close();
	//timer
	timespec_get(&sts, TIME_UTC);
	Gauss_A3(n);
	timespec_get(&ets, TIME_UTC);
	print_result("arm gauss A3");

		for (int i = 1; i <= n; ++i) {
			for (int j = 1; j <= n; ++j)
				fout << nums[i][j] << " ";
			fout << endl;
		}
	fout.close();
	memset(nums, 0, sizeof nums);

	fin.open("input.txt");
	fout.open("output.txt");
	fin >> n;
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= n; ++j)
			fin >> nums[i][j];
	fin.close();
	//timer
	timespec_get(&sts, TIME_UTC);
	Gauss_A4(n);
	timespec_get(&ets, TIME_UTC);
	print_result("arm gauss A4");

		for (int i = 1; i <= n; ++i) {
			for (int j = 1; j <= n; ++j)
				fout << nums[i][j] << " ";
			fout << endl;
		}
	fout.close();
	memset(nums, 0, sizeof nums);
}